package com.czg.jsonschema2lombokpojo.rules;

import com.czg.jsonschema2lombokpojo.Schema;
import com.czg.jsonschema2lombokpojo.config.GenerationConfig;
import com.fasterxml.jackson.databind.JsonNode;
import com.sun.codemodel.JType;

import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;

/**
 * format规则
 *
 * @author czg
 */
public class FormatRule implements Rule<JType, JType> {

    public static String ISO_8601_DATE_FORMAT = "yyyy-MM-dd";
    public static String ISO_8601_TIME_FORMAT = "HH:mm:ss.SSS";
    public static String ISO_8601_DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";

    private final RuleFactory ruleFactory;
    private final Map<String, Class<?>> formatTypeMapping;

    protected FormatRule(RuleFactory ruleFactory) {
        this.ruleFactory = ruleFactory;
        this.formatTypeMapping = getFormatTypeMapping(ruleFactory.getGenerationConfig());
    }

    /**
     * 应用此schema规则执行所需的代码生成步骤。
     * <p>
     * 该规则将格式值映射为Java类型。默认情况下:
     * <ul>
     * <li>"format":"date-time" =&gt; {@link java.util.Date} or {@link java.sql.Timestamp}
     * <li>"format":"date" =&gt; {@link String} or {@link java.sql.Date}
     * <li>"format":"time" =&gt; {@link String} or {@link java.sql.Time}
     * <li>"format":"utc-millisec" =&gt; <code>long</code>
     * <li>"format":"regex" =&gt; {@link java.util.regex.Pattern}
     * <li>"format":"color" =&gt; {@link String}
     * <li>"format":"style" =&gt; {@link String}
     * <li>"format":"phone" =&gt; {@link String}
     * <li>"format":"uri" =&gt; {@link java.net.URI}
     * <li>"format":"email" =&gt; {@link String}
     * <li>"format":"ip-address" =&gt; {@link String}
     * <li>"format":"ipv6" =&gt; {@link String}
     * <li>"format":"host-name" =&gt; {@link String}
     * <li>"format":"uuid" =&gt; {@link java.util.UUID}
     * <li>other (unrecognised format) =&gt; baseType
     * </ul>
     *
     * @param nodeName 应用此格式的节点的名称
     * @param node     格式节点
     * @param parent   父节点
     * @param baseType 正在被格式化的类型
     *                 <code>{ "type" : "string", "format" : "uri" }</code>
     *                 baseType将是java.lang.String
     * @return 适用于格式值的Java类型
     */
    @Override
    public JType apply(String nodeName, JsonNode node, JsonNode parent, JType baseType, Schema schema) {

        Class<?> type = getType(node.asText());
        if (type != null) {
            JType jtype = baseType.owner()._ref(type);
            return jtype;
        } else {
            return baseType;
        }
    }

    private Class<?> getType(String format) {
        return formatTypeMapping.getOrDefault(format, null);
    }

    private static Map<String, Class<?>> getFormatTypeMapping(GenerationConfig config) {

        Map<String, Class<?>> mapping = new HashMap<>(14);
        mapping.put("date-time", java.sql.Timestamp.class);
        mapping.put("date", java.sql.Date.class);
        mapping.put("time", java.sql.Time.class);
        mapping.put("utc-millisec", Long.class);
        mapping.put("regex", Pattern.class);
        mapping.put("color", String.class);
        mapping.put("style", String.class);
        mapping.put("phone", String.class);
        mapping.put("uri", URI.class);
        mapping.put("email", String.class);
        mapping.put("ip-address", String.class);
        mapping.put("ipv6", String.class);
        mapping.put("host-name", String.class);
        mapping.put("uuid", UUID.class);
        return mapping;
    }
}
